/***************************************************************
*
* (c) 2008 Markus Dittrich 
*
* This program is free software; you can redistribute it 
* and/or modify it under the terms of the GNU General Public 
* License Version 3 as published by the Free Software Foundation. 
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License Version 3 for more details.
*
* You should have received a copy of the GNU General Public 
* License along with this program; if not, write to the Free 
* Software Foundation, Inc., 59 Temple Place - Suite 330, 
* Boston, MA 02111-1307, USA.
*
****************************************************************/

#ifndef GRAPHCANVAS_H
#define GRAPHCANVAS_H

/* boost include */
#include <boost/utility.hpp>

/** STL includes */
#include <map>
#include <vector>

/** QT includes */
#include <QColor>
#include <QPixmap>
#include <QPoint>
#include <QSize>
#include <QString>
#include <QWidget>
#include <QRect>

/** local includes */
#include "data_object.h"
#include "canvas_layout_manager.h"
#include "canvas_to_datamap.h"
#include "plot_properties.h"
#include "popup_info_widget.h"
#include "main_window.h"
#include "tick_label_manager.h"

/** a few forward declarations */
class QKeyEvent;
class QMouseEvent;
class QPaintEvent;
class QPainter;
class QPen;
class QPrinter;
class QTextDocument;
class QWheelEvent;
class Settings;


/*****************************************************************
 * convenience typedefs 
 *****************************************************************/
typedef std::vector<QPoint> pixelMask;


/***************************************************************
 * 
 * CraphCanvas is the widget on which the actual graph is
 * being plotted
 *
 ***************************************************************/
class GraphCanvas 
  : 
    public QWidget,
    public boost::noncopyable
{
  
  Q_OBJECT


  /* CanvasLayoutManager needs access to data for computing minmax */ 
  friend class CanvasLayoutManager;

    
public:

  explicit GraphCanvas(MainWindow* myParent, int xOrigin, int yOrigin,
    int aHeight, int aWidth, const DataMap& data,
    const PlotPropertiesMap& plotProperties,
    const std::vector<QString>& activeData, DataLabelManager& labels,
    const Settings& settings);
  bool Init();

  void mark_scaling_dirty();
  void print(QPrinter& aPrinter) const;
  void export_bitmap(QString& filename, QString& format) const;

  
public slots:

  void update_pixmap();

  /* functions handling manipulation of the data view */
  void zoom_in();
  void zoom_out();
  void pan_left();
  void pan_right();
  void pan_up();
  void pan_down();
  void reset_view();


signals:

  void mouse_moved(double newXPos, double newYPos);
  void zoom_event(int amount);
  void pan_x_event(int amount);
  void pan_y_event(int amount);
  void reset_canvas_view_event();
  void focus_region_event(double xmin, double xmax, double ymin, 
      double ymax);


protected:

  void paintEvent(QPaintEvent* anEvent);
  void resizeEvent(QResizeEvent* anEvent);
  void mouseDoubleClickEvent(QMouseEvent* event);
  void mousePressEvent(QMouseEvent* event);
  void mouseReleaseEvent(QMouseEvent* event);
  void mouseMoveEvent(QMouseEvent* event);
  void wheelEvent(QWheelEvent* event);
  void keyPressEvent(QKeyEvent* event);


private:

  /* indicate successful construction */
  int status_;

  /* pointer to our parent */
  QWidget* parent_;

  /* popup info window related function s*/
  void generate_popup_window_();
  void update_popup_window_(const QString& dataName, int row) const;
  void show_popup_window_(QMouseEvent* anEvent) const;

  /* check if a particular data set is hidden */
  bool is_hidden_(const QString& dataName) const;

  /* data retrieval */
  const DataObjectPtr retrieve_data_(const QString& dataName) const;

  /* member functions */
  void set_axes_dimensions_();
  void paint_background_(QPainter& aPainter);
  void draw_axes_(QPainter& aPainter);
  void draw_labels_(QPainter& aPainter);
  void draw_data_labels_(QPainter& aPainter, QTextDocument& textDoc);
  void draw_data_(QPainter& aPainter);
  void draw_individual_data_set_(
    QPainter& currentPainter, QString& dataName, 
    QPoint* dataPoints, int dataLength);

  void initialize_label_layout_();

  void draw_ticks_and_labels_(QPainter& aPainer);
  void draw_x_ticks_and_labels_(QPainter& aPainter);
  void draw_y_ticks_and_labels_(QPainter& aPainter);

  int get_canvas_x_coordinate_(double xPos) const;
  int get_canvas_y_coordinate_(double yPos) const;
  double get_canvas_x_data_(int xPos) const;
  double get_canvas_y_data_(int yPos) const;

  void setup_popUp_search_mask_();

  QPen get_tick_pen_();
  QPen get_axes_pen_();
  QRect get_canvas_data_clipper_();
  const PlotPropertiesPtr& retrieve_plot_properties_ 
    (QString dataName) const;
  const QColor& get_graph_color_(QString dataName) const;
  const QString& get_graph_style_(QString dataName) const;
  int get_line_width_(QString dataName) const;
  int get_circle_diameter_(QString dataName) const;

  /* rubber band related functions */
  void repaint_RubberBand_region_();

  /* canvas dimensions */
  int canvasOriginX_;
  int canvasOriginY_;
  int canvasWidth_;
  int canvasHeight_;

  /* axes dimensions -- this is the active plot area */
  int axesOriginX_;
  int axesOriginY_;
  int axesWidth_;
  int axesHeight_;

  /* arrays holding the pixel masks for searching the neighborhood
   * of a pixel for data points as well as sensitivity settings */
  std::vector<pixelMask> popUpSearchMask_;

  /* offset of x/y axes from edges of canvas */
  static const int AXESOFFSETX_ = 90;
  static const int AXESOFFSETY_ = 60;

  /* tick and axes properties */
  int xHalfTickLength_;
  int yHalfTickLength_;
  int tickPenWidth_;
  int axesPenWidth_;

  /* label properties */
  int labelFontSize_;

  /* status variables */
  bool wantDataInfoPopup_;
  bool rubberBandOn_;

  /* QRect representing rubber band for zooming */
  QRect rubberBand_;

  /* active background color */
  QColor canvasBackgroundColor_;

  /* popup window widget */ 
  PopUpInfoWidget* popUp_;

  /* TickLabelManager objects manage x/y-axis ticks */
  TickLabelManager xTickLabels_;
  TickLabelManager yTickLabels_;

  /* CanvasScalingManager computer the global data minmax */
  CanvasLayoutManager canvasLayout_;

  /* pixmap to do efficient double buffered drawing */
  QPixmap pixMap_;

  /* we cache the QPoints for all active graphs to speed
   * up redrawing */
  CanvasMapPtr canvasMap_;

  /* reference to container holding the data sets to be plotted */
  const DataMap& data_;

  /* reference to container holding the plot properties for
   * each data set */
  const PlotPropertiesMap& plotProperties_;

  /* reference to currently active data sets, i.e. ones that
   * have been completetly initialized */
  const std::vector<QString>& activeData_;

  /* reference to labels for canvas, axis, and data sets */
  DataLabelManager& labels_;

  /* reference to current settings */
  const Settings& settings_;
};



#endif
